package gui;

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Panel;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.Serializable;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.ScrollPaneConstants;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;

import brac.Bracketing;
import fn.Function;
import fn.Global;

public class MainFrame extends JFrame implements Serializable {

	private static final long serialVersionUID = 1309468020033462070L;

	private JPanel contentPane;
	private JMenuBar mnuBar;
	public PlotPanel plotPanel;
	public JLabel lblStatus;
	public JMenu mnHelp;
	public JMenuItem mntmAbout;
	public JSeparator separator;
	public JMenuItem mntmGuide;
	public JMenu mnProgram;
	public JSeparator separator_1;
	public JMenuItem mntmExit;
	public JScrollPane scrollPane;
	public JPanel panel;
	public JTabbedPane tabbedPane;
	public BraketingPanel braketingPanel;
	public InterpolationPanel interpolationPanel;
	public JButton btnSolve;
	public JButton btnReset;
	public JPanel pnlOut;
	public BracketingOutput bracketingOutput;
	private CardLayout layoutOut;
	private InterpolationOutput interpolationOutput;
	public JMenuItem mntmCalculationPrecision;
	public JMenuItem mntmPlotPrecision;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
					MainFrame frame = new MainFrame();
					frame.setVisible(true);
				} catch (Exception e) {
					System.err.println(e.getMessage());
				}
			}
		});
	}

	public MainFrame() {
		init();
	}

	private void init() {
		setPreferredSize(new Dimension(768, 512));
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 769, 512);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);

		plotPanel = new PlotPanel();
		plotPanel.toolBar.setBorder(UIManager.getBorder("ScrollPane.border"));
		plotPanel.setBackground(SystemColor.controlDkShadow);
		plotPanel.canvas.setBorder(null);
		plotPanel.setBorder(UIManager.getBorder("ScrollPane.border"));

		lblStatus = new JLabel("");
		lblStatus.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));

		scrollPane = new JScrollPane();
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

		pnlIndicator = new JPanel();
		pnlIndicator.setPreferredSize(new Dimension(23, 23));
		pnlIndicator.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
		GroupLayout gl_contentPane = new GroupLayout(contentPane);
		gl_contentPane.setHorizontalGroup(gl_contentPane.createParallelGroup(Alignment.LEADING).addGroup(
				gl_contentPane
						.createSequentialGroup()
						.addGroup(
								gl_contentPane
										.createParallelGroup(Alignment.LEADING)
										.addGroup(
												gl_contentPane.createSequentialGroup()
														.addComponent(scrollPane, GroupLayout.PREFERRED_SIZE, 289, GroupLayout.PREFERRED_SIZE)
														.addPreferredGap(ComponentPlacement.RELATED)
														.addComponent(plotPanel, GroupLayout.DEFAULT_SIZE, 447, Short.MAX_VALUE))
										.addGroup(
												gl_contentPane.createSequentialGroup()
														.addComponent(pnlIndicator, GroupLayout.PREFERRED_SIZE, 23, GroupLayout.PREFERRED_SIZE)
														.addPreferredGap(ComponentPlacement.RELATED)
														.addComponent(lblStatus, GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE))).addGap(0)));
		gl_contentPane.setVerticalGroup(gl_contentPane.createParallelGroup(Alignment.LEADING).addGroup(
				gl_contentPane
						.createSequentialGroup()
						.addGroup(
								gl_contentPane.createParallelGroup(Alignment.TRAILING).addComponent(scrollPane, GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
										.addComponent(plotPanel, GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE))
						.addPreferredGap(ComponentPlacement.RELATED)
						.addGroup(
								gl_contentPane.createParallelGroup(Alignment.TRAILING, false)
										.addComponent(pnlIndicator, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
										.addComponent(lblStatus, GroupLayout.DEFAULT_SIZE, 21, Short.MAX_VALUE))));
		GroupLayout gl_pnlIndicator = new GroupLayout(pnlIndicator);
		gl_pnlIndicator.setHorizontalGroup(gl_pnlIndicator.createParallelGroup(Alignment.LEADING).addGap(0, 10, Short.MAX_VALUE));
		gl_pnlIndicator.setVerticalGroup(gl_pnlIndicator.createParallelGroup(Alignment.LEADING).addGap(0, 10, Short.MAX_VALUE));
		pnlIndicator.setLayout(gl_pnlIndicator);

		panel = new JPanel();
		scrollPane.setViewportView(panel);

		tabbedPane = new JTabbedPane(JTabbedPane.TOP);
		tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);

		btnSolve = new JButton("Solve");
		btnSolve.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_btnSolve_actionPerformed(e);
			}
		});

		btnReset = new JButton("Reset");
		btnReset.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_btnReset_actionPerformed(e);
			}
		});

		pnlOut = new JPanel();
		layoutOut = new CardLayout();
		pnlOut.setLayout(layoutOut);
		GroupLayout gl_panel = new GroupLayout(panel);
		gl_panel.setHorizontalGroup(gl_panel.createParallelGroup(Alignment.TRAILING).addComponent(tabbedPane, GroupLayout.DEFAULT_SIZE, 270, Short.MAX_VALUE)
				.addGroup(gl_panel.createSequentialGroup().addGap(113).addComponent(btnReset).addPreferredGap(ComponentPlacement.RELATED).addComponent(btnSolve))
				.addComponent(pnlOut, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 270, Short.MAX_VALUE));
		gl_panel.setVerticalGroup(gl_panel.createParallelGroup(Alignment.LEADING).addGroup(
				gl_panel.createSequentialGroup().addComponent(tabbedPane, GroupLayout.PREFERRED_SIZE, 303, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addGroup(gl_panel.createParallelGroup(Alignment.BASELINE).addComponent(btnSolve).addComponent(btnReset))
						.addPreferredGap(ComponentPlacement.RELATED).addComponent(pnlOut, GroupLayout.DEFAULT_SIZE, 269, Short.MAX_VALUE)));

		pnlOut.add("Empty", new Panel());
		bracketingOutput = new BracketingOutput(plotPanel.canvas);
		pnlOut.add("Bracketing", bracketingOutput);
		interpolationOutput = new InterpolationOutput();
		pnlOut.add("Interpolation", interpolationOutput);

		braketingPanel = new BraketingPanel(plotPanel);
		tabbedPane.addTab("Bracketing", null, braketingPanel, null);

		interpolationPanel = new InterpolationPanel(plotPanel.canvas);
		tabbedPane.addTab("Interpolation", null, interpolationPanel, null);
		panel.setLayout(gl_panel);
		contentPane.setLayout(gl_contentPane);

		mnuBar = new JMenuBar();
		setJMenuBar(mnuBar);

		mnProgram = new JMenu("Program");
		mnuBar.add(mnProgram);

		mntmCalculationPrecision = new JMenuItem("Calculation precision...");
		mntmCalculationPrecision.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_mntmCalculationPrecision_actionPerformed(e);
			}
		});
		mnProgram.add(mntmCalculationPrecision);

		mntmPlotPrecision = new JMenuItem("Plot precision...");
		mntmPlotPrecision.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_mntmPlotPrecision_actionPerformed(e);
			}
		});
		mnProgram.add(mntmPlotPrecision);

		separator_1 = new JSeparator();
		mnProgram.add(separator_1);

		mntmExit = new JMenuItem("Exit");
		mntmExit.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_mntmExit_actionPerformed(e);
			}
		});
		mnProgram.add(mntmExit);

		mnHelp = new JMenu("Help");
		mnuBar.add(mnHelp);

		mntmAbout = new JMenuItem("About");
		mntmAbout.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_mntmAbout_actionPerformed(e);
			}
		});
		mnHelp.add(mntmAbout);

		separator = new JSeparator();
		mnHelp.add(separator);

		mntmGuide = new JMenuItem("Guide...");
		mntmGuide.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				do_mntmGuide_actionPerformed(e);
			}
		});
		mnHelp.add(mntmGuide);
	}

	@Override
	public void repaint() {
		super.repaint();
//		plotPanel.removeAll();
		plotPanel.addFn(((BraketingPanel) tabbedPane.getSelectedComponent()).getFn());
	}

	public Component getOut() {
		for (Component c : pnlOut.getComponents())
			if (c.isVisible())
				return c;
		return null;
	}

	public void setOut(int i) {
		Component[] cs = pnlOut.getComponents();
		for (int j = 0; j < cs.length; j++)
			cs[j].setVisible(i == j);
	}

	public void resetOut() {
		Component[] cs = pnlOut.getComponents();
		cs[0].setVisible(true);
		for (int j = 1; j < cs.length; j++)
			cs[j].setVisible(false);
		plotPanel.canvas.removeFnAll();
		plotPanel.canvas.removePointAll();
	}

	protected void do_btnSolve_actionPerformed(ActionEvent e) {
		do_btnReset_actionPerformed(e);
		long startTime = System.nanoTime();
		try {
			getOut();
			int method = tabbedPane.getSelectedIndex();
			setOut(method + 1);
			// BRACKETING
			if (method == 0) {
				Bracketing brak = ((BraketingPanel) tabbedPane.getSelectedComponent()).solve();
				plotPanel.canvas.removeFnAll();
				plotPanel.canvas.addFn(((BraketingPanel) tabbedPane.getSelectedComponent()).getFn());
				bracketingOutput.setOutput(brak);
			}
			// INTERPOLATION
			else {
				Function f = ((InterpolationPanel) tabbedPane.getSelectedComponent()).solve();
				Function err = ((InterpolationPanel) tabbedPane.getSelectedComponent()).error();
				plotPanel.removeFnAll();
				interpolationOutput.setFn(f);
				interpolationOutput.setErr(err);
				plotPanel.addFn(f);
				plotPanel.addFn(((InterpolationPanel) tabbedPane.getSelectedComponent()).originalFn());
			}
			String ms = ((System.nanoTime() - startTime) / 1000000) % 1000 + "";
			String s = ((System.nanoTime() - startTime) / 1000000000) + "";
			statusMessage("Successfully solved! Execution time : " + s + "s " + ms + "ms");
		} catch (Exception ex) {
			statusError("Malformed expressions or wrong parameters. Can't solve.");
		}
	}

	protected void do_btnReset_actionPerformed(ActionEvent e) {
		try {
			resetOut();
		} catch (Exception ex) {
			statusError("GUI error. You might experiecnce unexpected behaviour with the interface.");
		}
	}

	protected void do_mntmCalculationPrecision_actionPerformed(ActionEvent e) {
		try {
			Global.DEC_TOL = Integer.parseInt(JOptionPane.showInputDialog(this, "Fractions can be displyed in results up to 10^-x\n x = ?", Global.DEC_TOL));
		} catch (Exception ex) {
			statusError("Wrong exponent");
		}
	}

	protected void do_mntmPlotPrecision_actionPerformed(ActionEvent e) {
		try {
			Global.DEC_STR = Integer.parseInt(JOptionPane.showInputDialog(this, "Fractions can be displyed on plot up to 10^-x\n x = ?", Global.DEC_STR));
		} catch (Exception ex) {
			statusError("Wrong exponent");
		}
	}

	protected void do_mntmExit_actionPerformed(ActionEvent e) {
		try {
			System.exit(ABORT);
		} catch (Exception ex) {
			statusError("Can't exit.");
		}
	}

	protected void do_mntmAbout_actionPerformed(ActionEvent e) {
		try {
			String s = "";
			s += "Numerical Analysis Assginment - Bracketing & Interpolation\n";
			s += "* Version 0.9.0\n";
			s += "* A.Salah - M.Abo-Shamaa - M.Bassem - M.Ghareeb - Ploa\n";
			JOptionPane.showMessageDialog(this, s);
		} catch (Exception ex) {
			statusError("Can't open About.");
		}
	}

	protected void do_mntmGuide_actionPerformed(ActionEvent e) {
		try {
			Desktop.getDesktop().open(new File("UserGuide.pdf"));
		} catch (Exception ex) {
			statusError("\"UserGuide.pdf\" Missing");
		}
	}

	Timer t = new Timer(5000, new ActionListener() {

		@Override
		public void actionPerformed(ActionEvent paramActionEvent) {
			statusClear();
		}
	});
	public JPanel pnlIndicator;

	public void statusClear() {
		lblStatus.setText("");
		pnlIndicator.setBackground(getBackground());
	}

	public void statusMessage(String s) {
		lblStatus.setText(s);
		pnlIndicator.setBackground(getBackground());
		t.restart();
	}

	public void statusError(String s) {
		lblStatus.setText(s);
		pnlIndicator.setBackground(Color.RED);
		t.restart();
	}
}
